#include "SharedVariables.fxh"

float4x4 World;

float3 lightColor;
float lightRadius;

float3 lightPosition;

float angleCosine;
float decayExponent;

float3 spotDirection;

float3 cameraPosition;
float4x4 InverseViewProj;

float4x4 lightViewProj;
float DepthBias = 0.01f;

texture shadow;
sampler shadowSampler = sampler_state
{
    Texture = <shadow>;
    MinFilter = POINT;
    MagFilter = POINT;
    MipFilter = NONE;
    AddressU = Clamp;
    AddressV = Clamp;
};

sampler depthSampler = sampler_state
{
	Texture=(DepthRT);
	MAGFILTER = POINT;
	MINFILTER = POINT;
	MIPFILTER = POINT;
	AddressU = Clamp;
	AddressV = Clamp;
};

sampler diffuseSampler = sampler_state
{
	Texture=(DiffuseRT);
	MAGFILTER = POINT;
	MINFILTER = POINT;
	MIPFILTER = POINT;
	AddressU = Clamp;
	AddressV = Clamp;
};

sampler normalSampler = sampler_state
{
	Texture=(NormalRT);
	MAGFILTER = POINT;
	MINFILTER = POINT;
	MIPFILTER = POINT;
	AddressU = Clamp;
	AddressV = Clamp;
};

struct SpotVSInput
{
    float3 Position : POSITION0;
};

struct SpotVSOutput
{
    float4 Position : POSITION0;
    float4 ScreenPosition : TEXCOORD0;
};

SpotVSOutput SpotVS(SpotVSInput input)
{
    SpotVSOutput output;

    float4 worldPosition = mul(float4(input.Position, 1), World);
    output.Position = mul(worldPosition, ViewProj);
    output.ScreenPosition = output.Position;

    return output;
}

float4 SpotPS(SpotVSOutput input) : COLOR0
{
	float4 position;
	float3 normal;
	float specularPower, specularIntensity;
	
	FillVariables(input.ScreenPosition, normalSampler, diffuseSampler, depthSampler, InverseViewProj, normal, specularPower, specularIntensity, position);
	
	float3 lightVector = lightPosition - position;
	float distance = length(lightVector);
	lightVector = normalize(lightVector);
	float SdL = dot(spotDirection, -lightVector);
	
	// Find the position of this pixel in light space
    float4 lightingPosition = mul(position, lightViewProj);
    lightingPosition.xyz /= lightingPosition.w;
    
    // Find the position in the shadow map for this pixel
    float2 ShadowTexCoord = 0.5f * (float2(lightingPosition.x, -lightingPosition.y) + 1.0f);
	ShadowTexCoord -= halfPixel;

    // Get the current depth stored in the shadow map
    float shadowDepth = tex2D(shadowSampler, ShadowTexCoord).r;
    
    // Calculate the current pixel depth
    // The bias is used to prevent folating point errors that occur when
    // the pixel of the occluder is being drawn
    float ourdepth = lightingPosition.z - DepthBias;
	
	float4 color = float4(0,0,0,0);
	
	if (SdL >= angleCosine && distance <= lightRadius && ourdepth <= shadowDepth) {
		float spotIntensity = pow(SdL, decayExponent);
		color = LightEquation(lightPosition, position, lightRadius, normal, lightColor, cameraPosition, specularIntensity, specularPower, spotIntensity);
	}
	
	return color;
}

technique SpotLight
{
	pass Pass0
	{
		VertexShader = compile vs_3_0 SpotVS();
		PixelShader = compile ps_3_0 SpotPS();
	}
}